﻿/*
 *	Copyright (c) 2009 Queensland University of Technology. All rights reserved.
 *	The QUT Bioinformatics Collection is open source software released under the 
 *	Microsoft Public License (Ms-PL): http://www.microsoft.com/opensource/licenses.mspx.
 */
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace QUT.Bio.SilverMap {

	/// <summary>
	/// Non-linear, invertible, scaling function that maps node edges
	/// to the interval [0,1].
	/// </summary>

	public abstract class Normalizer : INotifyPropertyChanged {
		private Stretcher stretcher;
		protected double lowerBound;
		protected double upperBound;
		
		public Normalizer( 			
			double lowerBound,
			double upperBound,
			Stretcher stretcher
		) {
			this.lowerBound = lowerBound;
			this.upperBound = upperBound;
			this.stretcher = stretcher;
		}

		public abstract double Map( double x );
		
		public abstract double InverseMap( double x );

		public double Normalize( double x ) {
			return stretcher.StretchOut( Map(x) );
		}

		public double Denormalize( double x ) {
			return InverseMap( stretcher.StretchIn( x ) );
		}

		public event PropertyChangedEventHandler PropertyChanged;

		protected void NotifyPropertyChanged( string field ) {
			if ( PropertyChanged != null ) {
				PropertyChanged( this, new PropertyChangedEventArgs( field ) );
			}
		}

		public double LowerBound {
			get {
				return lowerBound;
			}
			set {
				lowerBound = value;
				NotifyPropertyChanged( "LowerBound" );
			}
		}

		public double UpperBound {
			get {
				return upperBound;
			}
			set {
				upperBound = value;
				NotifyPropertyChanged( "UpperBound" );
			}
		}
	}

	public class LogarithmicNormalizer : Normalizer {

		public LogarithmicNormalizer(
			double lowerBound,
			double upperBound,
			Stretcher stretcher
		)
			: base( lowerBound, upperBound, stretcher )
		{}

		public override double Map( double x ) {
			if ( x < lowerBound ) {
				return 0;
			}

			if ( x > upperBound ) {
				return 1;
			}

			return Math.Log( x / lowerBound ) / Math.Log( upperBound / lowerBound );
		}

		public override double InverseMap( double x ) {
			if ( x >= 1.0 ) {
				return upperBound;
			}

			if ( x < Map( lowerBound ) ) {
				return lowerBound;
			}

			double a = upperBound / lowerBound;
			double b = Math.Log(a);
			double c = x * b;
			double d = Math.Log(lowerBound) + c;
			double e = Math.Exp(d);
			return e;
		}
	}

}
